#include "unixhead.h"

#include <nlohmann/json.hpp>
#include <workflow/WFFacilities.h>
#include <workflow/WFHttpServer.h>

#include <vector>
#include <iostream>
using namespace std;
using Json = nlohmann::json;

static WFFacilities::WaitGroup waitGroup(1);

void sighandler(int signum)
{
    cout << "wait group done\n";
    (void)signum;
    waitGroup.done();
}

void process(WFHttpTask * serverTask)
{
    cout << "process function is running\n";
    //0. 错误检测 ...
    //...
    //1. 解析请求
    auto req = serverTask->get_req();
    auto resp = serverTask->get_resp();//还未填充信息
    //http://192.168.30.128:8888/file/mupload/init?username=lwh
    string method = req->get_method();
    string uri = req->get_request_uri();
    string path = uri.substr(0, uri.find("?"));
    cout << "method:" << method << endl;
    cout << "path:" << path << endl;

    if(method == "POST" && path == "/file/mupload/init") {
        //1. 获取用户名
        string usernameKV = uri.substr(uri.find("?") + 1);
        string username = usernameKV.substr(usernameKV.find("=") + 1);
        cout << "username:" << username << endl;
        //2. 获取文件信息, 存储在报文体中
        const void * body = nullptr;       
        size_t sz = 0;
        req->get_parsed_body(&body, &sz);
        string fileJson(static_cast<const char*>(body));
        //cout << "fileJson:" <<  fileJson << endl;

        //3. 生成uploadID
        time_t secs = time(nullptr);
        struct tm * curtime = localtime(&secs);
        char buff[128] = {0};
        sprintf(buff, "%s%02d:%02d:%02d", username.c_str(),
                curtime->tm_hour, curtime->tm_min, curtime->tm_sec);
        string uploadID(buff);
        cout << "uploadID:" << uploadID << endl;
        //4. 生成分片信息
        Json fileInfo = Json::parse(fileJson);
        string fileName = fileInfo["filename"];
        string fileHash = fileInfo["filehash"];
        long fileSize = fileInfo["filesize"];
        /* cout << "fileName:" << fileName << endl; */
        /* cout << "fileHash:" << fileHash << endl; */
        /* cout << "fileSize:" << fileSize << endl; */
        size_t chunksize = 1024 * 1024;
        size_t chunkcount  = fileSize / chunksize + (fileSize % chunksize ? 1 : 0);
        cout << "chunkcount:" << chunkcount << endl;
        //5. 构造一个JSON对象，生成响应信息
        fileInfo["uploadID"] = uploadID;
        fileInfo["chunkcount"] = chunkcount;
        fileInfo["chunksize"] = chunksize;
        fileInfo["status"] = "OK";
        string chunkinfo = fileInfo.dump(2);
        cout << "chunkinfo: \n" << chunkinfo << endl;
        resp->append_output_body(chunkinfo);
        //6. 将分片信息存储到Redis中
        string url("redis://127.0.0.1:6379");
        auto redisTask = WFTaskFactory::create_redis_task(url, 0, nullptr);
        string cmd("HSET");
        vector<string> params{
            uploadID,
            "filename", fileName,
            "filehash", fileHash,
            "filesize", to_string(fileSize),
            "chunksize", to_string(chunksize),
            "chunkcount", to_string(chunkcount)
        };
        redisTask->get_req()->set_request(cmd, params);
        series_of(serverTask)->push_back(redisTask);
    } 
    else if(method == "POST" && path == "/file/mupload/uppart") {
        //http://192.168.30.128:8888/file/mupload/uppart?uploadID=lwh16:26&chunkidx=0
        //1. 解析请求，获取uploadID和分片索引
        string queryKV = uri.substr(uri.find("?") + 1);
        string uploadIDKV = queryKV.substr(0, queryKV.find("&"));
        string uploadID = uploadIDKV.substr(uploadIDKV.find("=") + 1);

        string chunkidxKV = queryKV.substr(queryKV.find("&") + 1);
        string chunkidx = chunkidxKV.substr(chunkidxKV.find("=") + 1);
        cout << "uploadID:" << uploadID << endl;
        cout << "chunkidx:" << chunkidx << endl;
        //2. 获取分片的数据
        const void * body = nullptr;
        size_t sz = 0;
        req->get_parsed_body(&body, &sz);
        //3. 存储数据
        //3.1 创建以uploadID为名字的目录
        mkdir(uploadID.c_str(), 0755);
        //3.2 写入本地文件
        string chunkname = uploadID + "/" + chunkidx;
        int fd = open(chunkname.c_str(),  O_RDWR|O_CREAT, 0664);
        if(fd < 0) {
            perror("open");
            return;
        }
        int ret = write(fd, body, sz);//写入到服务器的本地文件
        cout << "write: "  << ret << " bytes." << endl;
        close(fd);
        //4. 将分片信息存储到Redis中
        string url("redis://127.0.0.1:6379");
        auto redisTask = WFTaskFactory::create_redis_task(url, 0, nullptr);
        string cmd("HSET");
        vector<string> params{
            uploadID,
            "chunkidx_" + chunkidx,  "1"
        };
        redisTask->get_req()->set_request(cmd, params);
        series_of(serverTask)->push_back(redisTask);
        //5. 生成响应信息
        string respMsg = "uplaod fragment " + chunkidx + " success!";  
        resp->append_output_body(respMsg);
    } else if(method == "GET" && path == "/file/mupload/complete") {

    }
}

int main()
{
    signal(SIGINT, sighandler);

    WFHttpServer server(process);

    //start的返回值监听成功返回值为0
    if(0 == server.start(8888)) {
        waitGroup.wait();
        server.stop();   
    } else {
        cout << "server start error!\n";
    }

    return 0;
}
